using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Caliburn.Micro;
using MediaOwl.Common;
using MediaOwl.Common.Messages;
using MediaOwl.Common.ScreenManagement;
using MediaOwl.Common.ViewModels;
using MediaOwl.LastFm.Data;
using MediaOwl.LastFm.Model;
using MediaOwl.LastFm.Resources;

namespace MediaOwl.LastFm.ViewModels
{
    [Export, PartCreationPolicy(CreationPolicy.NonShared)]
    public class MusicTrackSingleViewModel : Workitem<LastFmViewModel>
    {
        #region Fields
        private readonly ILastFmDataRepository repository;
        private readonly IEventAggregator eventAggregator;

        #endregion

        #region Constructor

        [ImportingConstructor]
        public MusicTrackSingleViewModel(ILastFmDataRepository repository, IEventAggregator eventAggregator)
        {
            this.repository = repository;
            this.eventAggregator = eventAggregator;
        }

        #endregion

        #region Properties & Backingfields

        private Track currentTrack;
        public Track CurrentTrack
        {
            get { return currentTrack; }
            set
            {
                currentTrack = value;
                NotifyOfPropertyChange(() => CurrentTrack);
            }
        }

        public IList<Tag> Tags
        {
            get { return CurrentTrack == null ? null : CurrentTrack.Tags; }
        }
        public IList<Track> SimilarTracks
        {
            get { return CurrentTrack == null ? null : CurrentTrack.SimilarTracks; }
        }

        public bool CanShowAlbum
        {
            get
            {
                if (CurrentTrack == null)
                    return false;

                if (string.IsNullOrEmpty(CurrentTrack.AlbumName)
                    && string.IsNullOrEmpty(CurrentTrack.ArtistName))
                    return false;

                if (string.IsNullOrEmpty(CurrentTrack.AlbumMusicBrainzId))
                    return false;

                return true;
            }
        }
        public bool CanShowArtist
        {
            get
            {
                if (CurrentTrack == null)
                    return false;
                return !string.IsNullOrEmpty(CurrentTrack.ArtistName);
            }
        }
        #endregion

        #region Methods

        public void WithTrack(Track track)
        {
            if (track == null)
                return;
            DisplayName = track.Name;
            Run.Coroutine(FetchInfo(track));
        }

        public IEnumerator<IResult> FetchInfo(Track track)
        {
            yield return Show.Busy(this);

            yield return repository.GetTrack(track,
                                             x => CurrentTrack = track,
                                             x => eventAggregator.Publish(new ErrorMessage(x)));

            if (CurrentTrack != null)
            {
                yield return repository.GetSimilarTracks(CurrentTrack,
                                                         x => CurrentTrack.SimilarTracks = x.ToList(),
                                                         x => eventAggregator.Publish(new ErrorMessage(x)));

                NotifyOfPropertyChange(() => Tags);
                NotifyOfPropertyChange(() => SimilarTracks);
                NotifyOfPropertyChange(() => CanShowAlbum);
                NotifyOfPropertyChange(() => CanShowArtist);
            }
            yield return Show.NotBusy(this);
        }

        public IEnumerator<IResult> ShowArtist()
        {
            yield return Show.Busy(this);

            Artist artist = null;
            yield return string.IsNullOrEmpty(CurrentTrack.AlbumMusicBrainzId)
                             ? repository.GetArtist(CurrentTrack.ArtistName, false, x => artist = x,
                                                    x => eventAggregator.Publish(new ErrorMessage(x)))
                             : repository.GetArtist(CurrentTrack.ArtistMusicBrainzId, true, x => artist = x,
                                                    x => eventAggregator.Publish(new ErrorMessage(x)));
            yield return Show.NotBusy(this);
            if (artist != null)
            {
                yield return Show.Child<MusicArtistSingleViewModel>(Helper.GetScreenId(artist))
                .In(Parent)
                .Configured(x => x.WithArtist(artist));
            }
        }

        public IEnumerator<IResult> ShowAlbum()
        {
            yield return Show.Busy(this);
            Album album = null;

            yield return repository.GetAlbum(CurrentTrack.AlbumName,
                                    CurrentTrack.ArtistName,
                                    x => album = x,
                                    x => eventAggregator.Publish(new ErrorMessage(x)),
                                    CurrentTrack.AlbumMusicBrainzId);

            yield return Show.NotBusy(this);
            if (album != null)
            {
                yield return Show.Child<MusicAlbumSingleViewModel>(Helper.GetScreenId(album))
                .In(Parent)
                .Configured(x => x.WithAlbum(album));
            }
        }

        public IEnumerator<IResult> OpenPicture()
        {
            yield return Show.Busy(this);
            yield return Show.Child<ShowPictureSingleViewModel>(Helper.GetScreenId(CurrentTrack.PictureLarge))
                .In(Parent)
                .Configured(x => x.WithPicture(CurrentTrack.PictureLarge, string.Format(Captions.PictureTitle, CurrentTrack.Name)));
            yield return Show.NotBusy(this);
        }

        public IEnumerator<IResult> OpenSimilar(object selectedItem)
        {
            if (selectedItem is Track)
            {
                yield return Show.Child<MusicTrackSingleViewModel>(Helper.GetScreenId((Track)selectedItem))
                    .In(Parent)
                    .Configured(x => x.WithTrack((Track)selectedItem));
            }
        }

        public IEnumerator<IResult> OpenTag(object selectedItem)
        {
            if (selectedItem is Tag)
            {
                yield return Show.Child<MusicTagSingleViewModel>(Helper.GetScreenId((Tag)selectedItem))
                    .In(Parent)
                    .Configured(x => x.WithTag((Tag)selectedItem));
            }
        }

        #endregion
    }
}